/*********************************************************************
 * Copyright (C) 2003 Andrew Khan
 * <p>
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * <p>
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * <p>
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 ***************************************************************************/

package jxl.biff.drawing;

import jxl.biff.IntegerHelper;
import jxl.common.Logger;


/**
 * A single record from an Escher stream.  Basically this a container for
 * the header data for each Escher record
 */
final class EscherRecordData {
    /**
     * The logger
     */
    private static Logger logger = Logger.getLogger(EscherRecordData.class);

    /**
     * The byte position of this record in the escher stream
     */
    private int pos;

    /**
     * The instance value
     */
    private int instance;

    /**
     * The version value
     */
    private int version;

    /**
     * The record id
     */
    private int recordId;

    /**
     * The length of the record, excluding the 8 byte header
     */
    private int length;

    /**
     * The length of the stream
     */
    private int streamLength;

    /**
     * Indicates whether this record is a container
     */
    private boolean container;

    /**
     * The type of this record
     */
    private EscherRecordType type;

    /**
     * A handle back to the drawing group, which contains the entire escher
     * stream byte data
     */
    private EscherStream escherStream;

    /**
     * Constructor
     *
     * @param dg the escher stream data
     * @param p the current position in the stream
     */
    public EscherRecordData(EscherStream dg, int p) {
        escherStream = dg;
        pos = p;
        byte[] data = escherStream.getData();

        streamLength = data.length;

        // First two bytes contain instance and version
        int value = IntegerHelper.getInt(data[pos], data[pos + 1]);

        // Instance value is the first 12 bits
        instance = (value & 0xfff0) >> 4;

        // Version is the last four bits
        version = value & 0xf;

        // Bytes 2 and 3 are the record id
        recordId = IntegerHelper.getInt(data[pos + 2], data[pos + 3]);

        // Length is bytes 4,5,6 and 7
        length = IntegerHelper.getInt(data[pos + 4], data[pos + 5],
                data[pos + 6], data[pos + 7]);

        if (version == 0x0f) {
            container = true;
        } else {
            container = false;
        }
    }

    /**
     * Constructor
     *
     * @param t the type of the escher record
     */
    public EscherRecordData(EscherRecordType t) {
        type = t;
        recordId = type.getValue();
    }

    /**
     * Determines whether this record is a container
     *
     * @return TRUE if this is a container, FALSE otherwise
     */
    public boolean isContainer() {
        return container;
    }

    /**
     * Accessor for the length, excluding the 8 byte header
     *
     * @return the length excluding the 8 byte header
     */
    public int getLength() {
        return length;
    }

    /**
     * Accessor for the record id
     *
     * @return the record id
     */
    public int getRecordId() {
        return recordId;
    }

    /**
     * Accessor for the drawing group stream
     *
     * @return the drawing group stream
     */
    EscherStream getDrawingGroup() {
        return escherStream;
    }

    /**
     * Gets the position in the stream
     *
     * @return the position in the stream
     */
    int getPos() {
        return pos;
    }

    /**
     * Gets the escher type of this record
     *
     * @return the escher type
     */
    EscherRecordType getType() {
        if (type == null) {
            type = EscherRecordType.getType(recordId);
        }

        return type;
    }

    /**
     * Gets the instance value
     *
     * @return the instance value
     */
    int getInstance() {
        return instance;
    }

    /**
     * Sets whether or not this is a container - called when writing
     * out an escher stream
     *
     * @param c TRUE if this is a container, FALSE otherwise
     */
    void setContainer(boolean c) {
        container = c;
    }

    /**
     * Called from the subclass when writing to set the instance value
     *
     * @param inst the instance
     */
    void setInstance(int inst) {
        instance = inst;
    }

    /**
     * Called when writing to set the length of this record
     *
     * @param l the length
     */
    void setLength(int l) {
        length = l;
    }

    /**
     * Called when writing to set the version of this record
     *
     * @param v the version
     */
    void setVersion(int v) {
        version = v;
    }

    /**
     * Adds the 8 byte header data on the value data passed in, returning
     * the modified data
     *
     * @param d the value data
     * @return the value data with the header information
     */
    byte[] setHeaderData(byte[] d) {
        byte[] data = new byte[d.length + 8];
        System.arraycopy(d, 0, data, 8, d.length);

        if (container) {
            version = 0x0f;
        }

        // First two bytes contain instance and version
        int value = instance << 4;
        value |= version;
        IntegerHelper.getTwoBytes(value, data, 0);

        // Bytes 2 and 3 are the record id
        IntegerHelper.getTwoBytes(recordId, data, 2);

        // Length is bytes 4,5,6 and 7
        IntegerHelper.getFourBytes(d.length, data, 4);

        return data;
    }

    /**
     * Accessor for the header stream
     *
     * @return the escher stream
     */
    EscherStream getEscherStream() {
        return escherStream;
    }

    /**
     * Gets the data that was read in, excluding the header data
     *
     * @return the value data that was read in
     */
    byte[] getBytes() {
        byte[] d = new byte[length];
        System.arraycopy(escherStream.getData(), pos + 8, d, 0, length);
        return d;
    }

    /**
     * Accessor for the stream length
     *
     * @return the stream length
     */
    int getStreamLength() {
        return streamLength;
    }
}
